# -*- coding: utf-8 -*-
"""
    xfree.utils.markup
    ~~~~~~~~~~~~~~~~~~~~~
    文件描述：一个与标记（markup）相关的模块。
    作者：xfree
    邮箱：cy_83k@qq.com

"""

import logging
# 导入Mistune，这是一个轻量级的Markdown解析器
import mistune
# 从Flask框架导入url_for函数，用于生成URL
from flask import url_for
# 导入Markup类，用于处理安全的HTML标记
from markupsafe import Markup
# 导入HookimplMarker，用于实现插件钩子机制
from pluggy import HookimplMarker
# 从Pygments库导入用于代码高亮的函数和类
from pygments import highlight
from pygments.formatters import HtmlFormatter
from pygments.lexers import get_lexer_by_name
from pygments.util import ClassNotFound

# 创建一个HookimplMarker实例，用于标识这是xfree插件系统中的钩子实现
impl = HookimplMarker("xfree")

# 获取名为当前模块名的日志记录器
logger = logging.getLogger(__name__)

# 定义一个正则表达式，用于匹配用户名（不区分大小写）
_re_user = r"(?i)@(\w+)"


def parse_user_link(inline, match, state):
    """
    解析用户链接的函数

    :param inline: Mistune的内联解析器对象
    :param match: 正则表达式匹配对象
    :param state: 解析状态
    :return: 返回一个包含链接类型、链接地址和原始匹配字符串的元组
    """
    # 根据用户名生成用户资料页面的URL（内部URL）
    url = url_for("user.profile", username=match.group(1), _external=False)
    return "link", url, match.group(0)


def plugin_userify(md):
    """
    Mistune插件，将@username引用转换为链接

    :param md: Mistune的Markdown解析器对象
    """
    # 在Mistune的内联规则中注册一个名为"xfree_user_link"的规则
    md.inline.register_rule("xfree_user_link", _re_user, parse_user_link)
    # 将"xfree_user_link"规则添加到内联规则列表中
    md.inline.rules.append("xfree_user_link")


# 定义默认的插件列表
DEFAULT_PLUGINS = [
    "url",
    "strikethrough",
    "spoiler",
    "subscript",
    "superscript",
    "insert",
    "mark",
    "abbr",
    "def_list",
    "task_lists",
    "table",
    "footnotes",
]


class xfreeRenderer(mistune.HTMLRenderer):
    """
    Mistune渲染器，使用Pygments进行代码高亮
    """

    def __init__(self, **kwargs):
        """
        初始化函数
        """
        # 调用父类的初始化方法
        super(xfreeRenderer, self).__init__(**kwargs)

    def block_code(self, code, info=None):
        """
        处理代码块的方法

        :param code: 代码块内容
        :param info: 代码块语言信息（如果有）
        :return: 返回经过处理的代码块HTML表示
        """
        if info:
            try:
                # 根据代码块语言信息获取相应的词法分析器
                lexer = get_lexer_by_name(info, stripall=True)
            except ClassNotFound:
                # 如果找不到相应的词法分析器，设置为None
                lexer = None
        else:
            lexer = None
        if not lexer:
            # 如果没有词法分析器，返回普通的<pre><code>包裹的代码
            return "\n<pre><code>%s</code></pre>\n" % mistune.escape(code)
        # 创建一个HTML格式化器
        formatter = HtmlFormatter()
        # 使用Pygments进行代码高亮并返回结果
        return highlight(code, lexer, formatter)


@impl
def xfree_load_post_markdown_class():
    """
    钩子函数，返回用于帖子的Markdown渲染器类
    """
    return xfreeRenderer


@impl
def xfree_load_nonpost_markdown_class():
    """
    钩子函数，返回用于非帖子的Markdown渲染器类
    """
    return xfreeRenderer


@impl
def xfree_jinja_directives(app):
    """
    钩子函数，用于在Flask的Jinja2环境中设置Markdown渲染相关的过滤器

    :param app: Flask应用对象
    """
    # 获取用于帖子的Markdown渲染器类列表
    render_classes = app.pluggy.hook.xfree_load_post_markdown_class(app=app)
    # 复制默认插件列表
    plugins = DEFAULT_PLUGINS[:]
    # 调用钩子函数，允许插件修改用于帖子的Markdown插件列表
    app.pluggy.hook.xfree_load_post_markdown_plugins(plugins=plugins, app=app)
    # 创建一个用于帖子的Markdown渲染器，并将其作为"markup"过滤器添加到Jinja2环境中
    app.jinja_env.filters["markup"] = make_renderer(render_classes, plugins)

    # 获取用于非帖子的Markdown渲染器类列表
    render_classes = app.pluggy.hook.xfree_load_nonpost_markdown_class(app=app)
    # 再次复制默认插件列表
    plugins = DEFAULT_PLUGINS[:]
    # 调用钩子函数，允许插件修改用于非帖子的Markdown插件列表
    plugins = app.pluggy.hook.xfree_load_nonpost_markdown_plugins(
        plugins=plugins, app=app
    )
    # 创建一个用于非帖子的Markdown渲染器，并将其作为"nonpost_markup"过滤器添加到Jinja2环境中
    app.jinja_env.filters["nonpost_markup"] = make_renderer(render_classes, plugins)


def make_renderer(classes, plugins):
    """
    创建Markdown渲染器的函数

    :param classes: Markdown渲染器类列表
    :param plugins: Markdown插件列表
    :return: 返回一个用于渲染Markdown文本的函数
    """
    # 创建一个新的渲染器类，继承自传入的类列表
    RenderCls = type("xfreeRenderer", tuple(classes), {})

    # 创建一个Markdown解析器，使用自定义的渲染器和插件列表
    markup = mistune.create_markdown(
        renderer=RenderCls(), plugins=plugins, escape=True, hard_wrap=True
    )
    # 返回一个函数，该函数接受Markdown文本并返回渲染后的HTML
    return lambda text: Markup(markup(text))